#ifndef __BLOCKQUEUE.HPP__
#define __BLOCKQUEUE.HPP__

#include <iostream>
#include <queue>
#include <pthread.h>

using namespace std;

template <typename T>
class BlockQueue
{
    private:
     bool IsFull()
     {
        return _block_queue.size()==_cap;
     }
     bool IsEmpty()
     {
        return _block_queue.empty();
     }

    public:
    BlockQueue(int cap)
    :_cap(cap)
    {
        pthread_mutex_init(&_mutex,nullptr);
        pthread_cond_init(&_consum_cond,nullptr);
        pthread_cond_init(&_product_cond,nullptr);
    }

    void Enqueue(const T& in)//进队列
    {
        //_block_queue是临界资源，需要上锁
        pthread_mutex_lock(&_mutex);
        while(IsFull())
        {   
            _product_wait++;
            pthread_cond_wait(&_product_cond,&_mutex);
            //如果队列满了就等待，释放曾经持有的锁
            //被唤醒之后自动下线运行，被唤醒之后自动去争夺锁
            _product_wait--;
        }

        _block_queue.push(in);
        if(_consum_wait>0)
            pthread_cond_signal(&_consum_cond);

        pthread_mutex_unlock(&_mutex);
    }

    void Pop(T* out)
    {
        //_block_queue是临界资源，需要上锁
        pthread_mutex_lock(&_mutex);
        while(IsEmpty())
        {   
            _consum_wait++;
            pthread_cond_wait(&_consum_cond,&_mutex);
            //如果队列满了就等待，释放曾经持有的锁
            //被唤醒之后自动下线运行，被唤醒之后自动去争夺锁
            _consum_wait--;
        }

        *out = _block_queue.front(); 
        _block_queue.pop();
        if(_product_wait>0)
            pthread_cond_signal(&_product_cond);

        pthread_mutex_unlock(&_mutex);
    }

    ~BlockQueue()
    {
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_consum_cond);
        pthread_cond_destroy(&_product_cond);
    }

    private:
    int _cap;//最大容量
    queue<T> _block_queue;
    pthread_mutex_t _mutex;
    pthread_cond_t _consum_cond;
    pthread_cond_t _product_cond;
    int _consum_wait;
    int _product_wait;
};


#endif
